package core.units;
import graphics.ImageHandler;
import graphics.SpriteHandler;

import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Vector;

import ai.WorldAI;


import core.*;
import core.actions.*;
import core.mountedWeapons.GenericMachinegun;
import core.mountedWeapons.GenericPistol;
import core.mountedWeapons.Howitzer;
import core.mountedWeapons.MountedWeapon;
import core.units.*;
import core.weapons.*;

public class Unit {
	SingleButtonGame main;
	public Player master;

	private Vector<MountedWeapon> weapons = new Vector<MountedWeapon>();
	
	protected int speed = 200, attackTimer=0;
	//public int team, player;
	protected int x, y;
	protected double dir=0;
	protected final int FACTOR=1000;
	protected int tX=0, tY=0;
	protected int health=100, maxHealth=100;
	protected boolean alive=false;
	public Rectangle bounds;
	protected int width = 30000, height = 30000;
	public boolean isSelectable = false;
	private String imageName = "iconTank1.png";
	private int imageId = 0;
	private int spriteId = -1;
	
	public ActionMap<Action> actionMap = new ActionMap<Action>();
	
	public Unit(int x1, int y1, Player m){
		this(new Point(x1, y1), new Point(x1, y1), m);
	}
	
	public Unit(Point inSpawnPoint, Point inTargetPoint, Player m){
		if(m != null){
			main=m.main;
			master=m;
			if(!main.units.contains(this))
				main.units.add(this);
		}
		//team=m.getTeam();
		//player=m.getPlayer();
		x=inSpawnPoint.x;
		y=inSpawnPoint.y;
		
		bounds=new Rectangle(x-width/2, y-height/2, width, height);
		setTarget(inTargetPoint);	
		//weapons.add(new Howitzer());  // Added weapon for testing
		//weapons.add(new GenericPistol(30, 100));
		setImageName(imageName);
		setDefaultActionMap();
	}
	public Unit(Point inSpawnPoint, Player m){
		this(inSpawnPoint, inSpawnPoint, m);
	}
	public void addWeapon(MountedWeapon w){
		weapons.add(w);
	}
	public void linkToPlayer(Player m){
		main=m.main;
		master = m;
		if(!main.units.contains(this))
			main.units.add(this);
		linkActions();
	}
	/**
	 * Links all current actions to the correct player. Should always be called after actions without any specific owner have been added.
	 */
	public void linkActions(){
		for(Action a : actionMap.getAllActions()){
			if(a!=null)
				a.setOwner(master);
		}
	}
	
	public void spawn(Point inSpawnPoint){
		x=inSpawnPoint.x;
		y=inSpawnPoint.y;
		setTarget(inSpawnPoint);
		health = maxHealth;
		alive = true;
	}
	
	public void nextFrame(){
		refreshBoundsPosition();
		
		for(int n = 0; n < main.units.size(); n++){
			if (main.units.get(n) != null&&main.units.get(n)!=this){
				if(main.units.get(n).bounds.intersects(bounds)){
					main.units.get(n).takeDamage(0);
					takeDamage(0);
				}
			}
		}
		if(tX == 0 && tY == 0){
			x=x+(int)(Math.cos(dir*3.1415*2)*speed);
			y=y+(int)(Math.sin(dir*3.1415*2)*speed);
		}
		
		else{
			
			double dx=tX-x;
			double dy=tY-y;
			double dist = Math.sqrt(dx*dx+dy*dy);
			dir = Math.atan2(dx, -dy)/(2*3.1415)-0.25;
			
			if(dist>speed){
				x=x+(int)(dx*speed/dist);
				y=y+(int)(dy*speed/dist);
			}
		}
		for(MountedWeapon w : weapons){
			w.nextFrame();
		}
		
		ai();
		autoFire();
	}
	public void autoFire(){
		/*attackTimer++;
		if(attackTimer>=35){
			main.attacks.add(new Bullet(x, y, master, angleTo(findNearestEnemy()), 10, 3000, 0.04, 500000));
			attackTimer=0;
		}*/
		for(MountedWeapon w : weapons){
			if(w.isReadyToFire()){
				w.fire(x, y, angleTo(findNearestEnemy()), master);
			}
		}
	}
	public void fireClose(int inX, int inY){
			main.attacks.add(new Bullet(x, y, master, angleTo(findNearestEnemy(inX, inY)), 10, 3000, 0.04, 500000));
	}
	public void ai(){}
	public void takeDamage(int dmgIn){
		health=health-dmgIn;
		if(health<=0){
			alive=false;			
		}
	}
	public int findNearestEnemy(){
		double shortestRange=0, range;
		int nearestUnit=0;
		double dx, dy;
		for(int c=0; c<main.units.size(); c++){
			if(main.units.get(c)!=null && main.units.get(c).isAlive() && main.units.get(c).getTeam()!=getTeam()){
				dx=main.units.get(c).getX()-x;
				dy=main.units.get(c).getY()-y;
				range=Math.sqrt(dx*dx+dy*dy);
				if(shortestRange==0 || shortestRange>=range){
					shortestRange=range;
					nearestUnit=c;
				}
			}
		}
		return nearestUnit;
	}
	public int findNearestEnemy(int inX, int inY){
		int shortestRange=0, range;
		int nearestUnit=0;
		int dx, dy;
		for(int c=0; c<main.units.size(); c++){
			if(main.units.get(c)!=null && main.units.get(c).isAlive() && main.units.get(c).getTeam()!=getTeam()){
				dx=main.units.get(c).getX()-inX;
				dy=main.units.get(c).getY()-inY;
				range=(int)Math.sqrt(dx*dx+dy*dy);
				if(shortestRange==0 || shortestRange>=range){
					shortestRange=range;
					nearestUnit=c;
				}
			}
		}
		return nearestUnit;
	}
	public double angleTo(int unitId){
		if(main.units.get(unitId) != null)
			return Math.atan2(main.units.get(unitId).getX()-x, -main.units.get(unitId).getY()+y)/(2*3.1415)-0.25;
		else
			return 0;
	}
	
	public void paint(Point screenOffset, int zoomDivider, Graphics g){
		if(imageName == null){
			g.setColor(master.getColor());		
			g.fillRect((x-screenOffset.x-15000)/zoomDivider, (y-screenOffset.y-10000)/zoomDivider, 30000/zoomDivider, 20000/zoomDivider);
			g.drawOval((tX-screenOffset.x)/zoomDivider-5, (tY-screenOffset.y)/zoomDivider-5, 10, 10);
			//g.drawString(""+getTeam(), (x-screenOffset.x)/zoomDivider-2, (y-screenOffset.y)/zoomDivider-15);
			g.setColor(Color.green);
			g.fillRect((x-screenOffset.x)/zoomDivider-10, (y-screenOffset.y)/zoomDivider-15, health*20/maxHealth, 3);
		}
		else{
			
			
			
			g.setColor(new Color(master.getColor().getRed(), master.getColor().getGreen(), master.getColor().getBlue(), 150));
			//g.fillOval((x-screenOffset.x-width*5/8)/zoomDivider, (y-screenOffset.y-height*1/4)/zoomDivider, width*10/8/zoomDivider, height/zoomDivider);
			//g.drawOval((x-screenOffset.x-width*5/8)/zoomDivider-3, (y-screenOffset.y-height*1/4)/zoomDivider-3, width*10/8/zoomDivider+6, height/zoomDivider+6);
			
			//g.fillOval((x-screenOffset.x-width*5/8)/zoomDivider, (y-screenOffset.y+height/3-width/2)/zoomDivider, width*10/8/zoomDivider, width*3/4/zoomDivider);
			//g.drawOval((x-screenOffset.x-width*5/8)/zoomDivider-3, (y-screenOffset.y+height/3-width/2)/zoomDivider-3, width*10/8/zoomDivider+6, width*3/4/zoomDivider+6);
			if(spriteId == -1){
				ImageHandler.getInstance().drawImage((x-screenOffset.x-width/2)/zoomDivider, (y-screenOffset.y-height/2)/zoomDivider, width/zoomDivider, height/zoomDivider, imageName, g);
			}
			else{
				SpriteHandler.getInstance().drawSprite((x-screenOffset.x-width/2)/zoomDivider, (y-screenOffset.y-height/2)/zoomDivider, width/zoomDivider, height/zoomDivider, dir, 0, spriteId, g);
			}
		
			drawInterface(screenOffset, zoomDivider, g);
			
			//int linex=(x-screenOffset.x)/zoomDivider+(int)(Math.cos(dir*3.1415*2)*speed/10);
			//int liney=(y-screenOffset.y)/zoomDivider+(int)(Math.sin(dir*3.1415*2)*speed/10);
			//g.drawLine((x-screenOffset.x)/zoomDivider, (y-screenOffset.y)/zoomDivider, linex, liney);
		}			
	}
	private void drawInterface(Point screenOffset, int zoomDivider, Graphics g){
		int iDist = height/2/zoomDivider;
		g.setColor(master.getColor());
		if(!(master instanceof WorldAI)){
			g.fillRoundRect((x-screenOffset.x)/zoomDivider-13, (y-screenOffset.y)/zoomDivider-iDist-6, 26, 12, 5, 5);
		}
		g.setColor(Color.black); 
		g.fillRect((x-screenOffset.x)/zoomDivider-11, (y-screenOffset.y)/zoomDivider-iDist-1, 22, 5);
		g.setColor(Color.green);
		g.fillRect((x-screenOffset.x)/zoomDivider-10, (y-screenOffset.y)/zoomDivider-iDist, health*20/maxHealth, 3);
	}
	public void changeDir(double newDir){
		dir = newDir;
		
	}
	public int getX(){
		return x;
	}
	public int getY(){
		return y;
	}
	public int getTeam(){
		return master.getTeam();
	}
	public Point getPoint() {
		return (new Point(getX(),getY()));
	}
	public void setTarget(int x1, int y1){
		tX=x1;
		tY=y1;
	}
	public void setTarget(Point inPoint){
		tX=inPoint.x;
		tY=inPoint.y;
	}
	public void stop(){
		setTarget(x,y);
	}
	public void pushX(int i){
		x=x+i;
		refreshBoundsPosition();
	}
	public void pushY(int i){
		y=y+i;
		refreshBoundsPosition();
	}
	public boolean isAlive(){
		return alive;
	}
	public boolean isDead() {
		if(alive) 
			return false;
		else
			return true;
	}
	private void refreshBoundsPosition(){
		bounds.setLocation(x-width/2, y-height/2);
	}
	public void setWidth(int w){
		width=w;
		bounds.width=w;
	}
	public void setHeight(int h){
		height=h;
		bounds.height=h;
	}
	
	protected void setDefaultActionMap(){
		actionMap.clear();
		actionMap.setWantedDepth(3);
		
		actionMap.add(new MoveHero());
		actionMap.add(new NextUnit());
		actionMap.add(new AddMachinegun());
		
		actionMap.add(new FireShotgun());		
		actionMap.add(new FireSniper());
		actionMap.add(new FireMissile());
		
		actionMap.add(new FireMortar());
		
	}
	public ActionMap<Action> getActionMap(){
		return actionMap;
	}

	public Player getMaster() {
		return master;
	}

	public void setMaster(Player master) {
		this.master = master;
	}

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getHealth() {
		return health;
	}

	public void setHealth(int health) {
		this.health = health;
	}

	public int getMaxHealth() {
		return maxHealth;
	}

	public void setMaxHealth(int maxHealth) {
		this.maxHealth = maxHealth;
	}

	public Rectangle getBounds() {
		return bounds;
	}

	public void setBounds(Rectangle bounds) {
		this.bounds = bounds;
	}

	public String getImageName() {
		return imageName;
	}

	public void setImageName(String imageName) {
		this.imageName = imageName;
		imageId = ImageHandler.getInstance().getIdOfImage(imageName);
	}
	public void setSpriteName(String spriteName) {
		spriteId = SpriteHandler.getInstance().getIdOfSprite(spriteName);
	}
	
}
